package jwlee.testxml;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class Dom4jUtils {
	private static final Logger logger = Logger.getLogger(Dom4jUtils.class.getName());

	/**
	 * 将文件读入到文档对象中
	 * 
	 * @param fileName
	 * @return
	 */
	public static Document read(String fileName) {
		SAXReader reader = new SAXReader();
		reader.setEncoding("UTF-8");
		Document document = null;
		try {
			document = reader.read(new File(fileName));
		} catch (DocumentException e) {
			logger.log(Level.SEVERE, e.getMessage());
		}
		return document;
	}

	/**
	 * 将流读入到文档对象中
	 * 
	 * @param is
	 * @return
	 */
	public static Document read(InputStream is) {
		SAXReader reader = new SAXReader();
		reader.setEncoding("UTF-8");
		Document document = null;
		try {
			document = reader.read(is);
		} catch (DocumentException e) {
			logger.log(Level.SEVERE, e.getMessage());
		}
		return document;
	}

	public static Element getElementByXpath(Document doc, String elementPath) {
		Element firstE = null;
		List nodeList = doc.selectNodes(elementPath);
		if (nodeList != null && !nodeList.isEmpty()) {
			firstE = (Element) nodeList.get(0);
		}
		return firstE;
	}

	public static Element getChildElementByXpath(Element parentE, String childPath) {
		Element firstE = null;
		List nodeList = parentE.selectNodes(childPath);
		if (nodeList != null && !nodeList.isEmpty()) {
			firstE = (Element) nodeList.get(0);
		}
		return firstE;

	}

	/**
	 * 将元素解析到VO
	 * 
	 * @param element
	 * @param vo
	 * @param attrPath
	 *            特殊情况[属性名:子路径]
	 */
	public static void parseElement2VO(Element element, Object vo, Map attrPath) {
		Method[] setMethods = vo.getClass().getMethods();
		for (int i = 0; i < setMethods.length; i++) {
			String setMethodName = setMethods[i].getName();
			if (!setMethodName.startsWith("set"))
				continue;

			Class[] paraTypes = setMethods[i].getParameterTypes();
			if (paraTypes.length != 1)
				continue;

			String attributeName = setMethodName.substring(3).trim();
			// set后面部分，首字母小写
			attributeName = attributeName.substring(0, 1).toLowerCase()
					+ attributeName.substring(1);

			// if (List.class.isAssignableFrom(paraTypes[0])) {
			// List nodeList = element.selectNodes("./" + attributeName);
			// }

			Element childE = getChildElementByXpath(element, "./" + attributeName);
			if (childE != null || "".equals(childE.getTextTrim())) {
				logger.info(childE.getName() + ":" + childE.getTextTrim());
				try {
					setAttrValue(childE, vo, setMethods[i]);
				} catch (Exception ex) {
					logger.log(Level.SEVERE, "方法调用异常" + ex.getMessage());
				}
			} else if (attrPath != null && attrPath.containsKey(attributeName)) {// 特殊的从map里面指定的路径找
				String childPath = (String) attrPath.get(attributeName);
				Element grandchildE = getChildElementByXpath(element, childPath);
				if (grandchildE != null) {
					logger.info(grandchildE.getName() + ":" + grandchildE.getTextTrim());
					try {
						setAttrValue(grandchildE, vo, setMethods[i]);
					} catch (Exception ex) {
						logger.log(Level.SEVERE, "方法调用异常" + ex.getMessage());
					}
				}
			}
		}

	}

	public static List parseElements2VOList(Document doc, Object vo, String elementPath) {
		List nodeList = doc.selectNodes(elementPath);
		return parseElements2VOList(nodeList, vo);
	}

	public static List parseElements2VOList(Element element, Object vo, String childPath) {
		List nodeList = element.selectNodes(childPath);
		return parseElements2VOList(nodeList, vo);
	}

	/**
	 * 将nodeList解析成voList
	 * 
	 * @param nodeList
	 * @param vo
	 * @return
	 */
	public static List parseElements2VOList(List nodeList, Object vo) {
		List voList = new ArrayList();
		Element element = null;
		for (int i = 0; i < nodeList.size(); i++) {
			element = (Element) nodeList.get(i);
			parseElement2VO(element, vo, null);
			voList.add(vo);
		}
		return voList;
	}

	/**
	 * 调用VO的setter方法将Element设置到对应属性上
	 * 
	 * @param ele
	 * @param vo
	 * @param setMethod
	 *            必须只有一个参数
	 * @return
	 * @throws Exception
	 */
	protected static boolean setAttrValue(Element ele, Object vo, Method setMethod)
			throws Exception {
		Class[] paraTypes = setMethod.getParameterTypes();
		if (paraTypes.length != 1)// 一般setter方法只有一个参数
			return false;
		Class paraType = paraTypes[0];

		String valueS = ele.getTextTrim();

		Object value = null;
		if (String.class.equals(paraType)) {
			value = valueS;
		} else if (Integer.class.equals(paraType)) {
			value = Integer.valueOf(valueS);
		} else if (Double.class.equals(paraType)) {
			value = Double.valueOf(valueS);
		} else if (Long.class.equals(paraType)) {
			value = Long.valueOf(valueS);
		} else if (Date.class.equals(paraType)) {
			DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
			value = dateFormat.parse(valueS);
		} else if (Calendar.class.equals(paraType)) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(new SimpleDateFormat("yyyyMMdd").parse(valueS));
			value = calendar;
		}

		setMethod.invoke(vo, value);
		return true;
	}

	private static void testParse() {
		try {
			BufferedReader reader = new BufferedReader(new FileReader("src/jwlee/testxml/files/school.xml"));
			String tempStr;
			StringBuffer ewXml = new StringBuffer();
			while ((tempStr = reader.readLine()) != null) {
				ewXml.append(tempStr).append("\n");
			}
			String sXml = ewXml.toString();
			logger.log(Level.INFO, sXml);

			Document doc = DocumentHelper.parseText(sXml);
			Element root = doc.getRootElement();

			Attribute arrRootCmd = root.attribute("cmd");
			logger.info("rootNmae = " + root.getName());
			String rootCmd = null;
			if(arrRootCmd != null){
				rootCmd = arrRootCmd.getValue();
			}
			logger.info("EW'cmd = " + rootCmd);
			Attribute arrRootVersion = root.attribute("version");
			String rootVersion = null;
			if(arrRootVersion != null){
				rootVersion = arrRootVersion.getValue();
			}
			logger.info("EW'version = " + rootVersion);

			Element eClass = root.element("class");
			logger.info("EW.class value =" + eClass.getTextTrim());

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		 testParse();
		//判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同，或是否是其超类或超接口。
		boolean b = List.class.isAssignableFrom(ArrayList.class);
		logger.info("" + b);//true
	}
}
